home *** CD-ROM | disk | FTP | other *** search
- /////////////////////////////////////////////////////////////
- // Flash Plugin and Player
- // Copyright (C) 1998,1999 Olivier Debon
- //
- // This program is free software; you can redistribute it and/or
- // modify it under the terms of the GNU General Public License
- // as published by the Free Software Foundation; either version 2
- // of the License, or (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- //
- // You should have received a copy of the GNU General Public License
- // along with this program; if not, write to the Free Software
- // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- //
- ///////////////////////////////////////////////////////////////
- // Author : Olivier Debon <odebon@club-internet.fr>
- //
- #include "swf.h"
-
- #ifndef NOSOUND
- #ifndef AMIGA
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/ioctl.h>
- #include <linux/soundcard.h>
- #else
- /* Amiga includes */
- extern "C" {
- #include <clib/alib_protos.h>
-
- #ifdef __PPC__
- #define DOS_DOSEXTENS_H
- #include </ADE/os-includeppc/proto/dos.h>
- #undef DOS_DOSEXTENS_H
- #include </ADE/os-includeppc/proto/exec.h>
- #else
- #include <clib/exec_protos.h>
- #endif
- #include <devices/audio.h>
- #include <exec/memory.h>
- #include <graphics/gfxbase.h>
- }
-
- struct channel_info {
- struct MsgPort *audio_mp;
- struct IOAudio *audio_io;
- BOOL sound_in_progress;
- };
-
- static struct channel_info channel_info[2] =
- {
- {FALSE, NULL, NULL},
- {FALSE, NULL, NULL},
- };
-
- static struct MsgPort *audio_mp = NULL;
- static struct IOAudio *audio_io = NULL;
- static BOOL audio_is_open = FALSE;
-
- extern struct GfxBase *GfxBase;
- static ULONG clock_constant;
- static ULONG amiga_period;
- static UBYTE sound_in_progress = 0;
- #endif // !AMIGA
- #endif // !NOSOUND
-
- #ifdef RCSID
- static char *rcsid = "$Id: sound.cc,v 1.11 1999/01/31 21:14:22 olivier Exp $";
- #endif
- #define PRINT 0
-
- //////////// SOUND
-
- Sound::Sound(long id) : Character(SoundType, id)
- {
- samples = 0;
- stereo = 0;
- soundRate = 0;
- sampleSize = 1;
- }
-
- Sound::~Sound()
- {
- if (samples) {
- delete samples;
- }
- }
-
- void
- Sound::setSoundFlags(long f) {
- switch (GET_SOUND_RATE_CODE(f)) {
- case 0:
- soundRate = 5500;
- break;
- case 1:
- soundRate = 11000;
- break;
- case 2:
- soundRate = 22000;
- break;
- case 3:
- soundRate = 44000;
- break;
- }
- if (f & soundIs16bit) {
- sampleSize = 2;
- }
- if (f & soundIsStereo) {
- stereo = 1;
- }
-
- #if PRINT
- printf("-----\nFlags = %2x\n", f);
- printf("Rate = %d kHz ", soundRate);
- printf("SampleSize = %d byte(s) ", sampleSize);
- if (f & soundIsStereo) {
- printf("Stereo ");
- } else {
- printf("Mono ");
- }
- if (f & soundIsADPCMCompressed) {
- printf("ADPCM\n");
- } else {
- printf("Raw\n");
- }
- #endif
- }
-
- char *
- Sound::setNbSamples(long n) {
- long size;
-
- nbSamples = n;
-
- size = nbSamples * (stereo ? 2 : 1) * sampleSize;
-
- samples = new char[ size ];
-
- memset((char *)samples,0, size);
-
- return samples;
- }
-
- long
- Sound::getRate() {
- return soundRate;
- }
-
- long
- Sound::getChannel() {
- return stereo ? 2 : 1;
- }
-
- long
- Sound::getNbSamples() {
- return nbSamples;
- }
-
- long
- Sound::getSampleSize() {
- return sampleSize;
- }
-
- char *
- Sound::getSamples() {
- return samples;
- }
-
- //////////// SOUND MIXER
-
- long SoundMixer::dsp = -1; // Init of descriptor
- long SoundMixer::blockSize = 0; // Driver sound buffer size
- long SoundMixer::nbInst = 0; // Nb SoundMixer instances
- long SoundMixer::sampleSize = 0;
- long SoundMixer::stereo = 0;
- long SoundMixer::soundRate = 0;
- char *SoundMixer::buffer = 0;
-
- SoundMixer::SoundMixer(char *device)
- {
- #ifndef NOSOUND
- #ifdef AMIGA
- dsp = -1;
- audio_is_open = FALSE;
- perror("Linux specific");
- #else
- int status;
- long fmt;
-
- list = 0; // No sound to play
-
- if (nbInst++) {
- // Device is already open
- return;
- }
-
- dsp = open(device,O_WRONLY);
- if (dsp < 0) {
- perror("open dsp");
- return;
- }
-
- // Reset device
- status = ioctl(dsp, SNDCTL_DSP_RESET);
- if (status < 0) perror("ioctl SNDCTL_DSP_RESET");
-
- // Set sample size
- fmt = AFMT_S16_LE;
- sampleSize = 2;
- status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
- if (status < 0) perror("ioctl SNDCTL_DSP_SETFMT");
-
- if (status) {
- fmt = AFMT_U8;
- sampleSize = 1;
- status = ioctl(dsp, SNDCTL_DSP_SETFMT, &fmt);
- if (status < 0) perror("ioctl SNDCTL_DSP_SETFMT");
- }
-
- // Set stereo channel
- stereo = 1;
- status = ioctl(dsp, SNDCTL_DSP_STEREO, &stereo);
-
- if (status) {
- stereo = 0;
- }
-
- // Set sound rate in Hertz
- soundRate = 11000;
-
- status = ioctl(dsp, SNDCTL_DSP_SPEED, &soundRate);
- if (status < 0) perror("ioctl SNDCTL_DSP_SPEED");
-
- // Get device buffer size
- status = ioctl(dsp, SNDCTL_DSP_GETBLKSIZE, &blockSize);
- if (status < 0) perror("ioctl SNDCTL_DSP_GETBLKSIZE");
- if (blockSize < 1024) {
- blockSize = 32768;
- }
- blockSize *= 2;
-
- buffer = (char *)malloc(blockSize);
- if (buffer == 0) {
- close(dsp);
- dsp = -1;
- }
-
- #if PRINT
- int caps;
-
- ioctl(dsp,SNDCTL_DSP_GETCAPS, &caps);
- printf("Audio capabilities = %x\n", caps);
- printf("Sound Rate = %d\n", soundRate);
- printf("Stereo = %d\n", stereo);
- printf("Sample Size = %d\n", sampleSize);
- printf("Buffer Size = %d\n", blockSize);
- #endif /* PRINT */
-
- #endif /* NOSOUND */
- #endif /* AMIGA */
- }
-
-
- SoundMixer::SoundMixer(int flags)
- {
- #ifndef NOSOUND
- #ifndef AMIGA
- dsp = -1;
- perror("Amiga specific");
- #else
- int status;
- long fmt;
-
- int i;
- UBYTE MyChannels [] = {1,2,4,8};
- UBYTE chans[1];
- struct channel_info *c;
-
- buffer1 = (char *) NULL;
- buffer2 = (char *) NULL;
-
- list = 0; // No sound to play
-
- if (nbInst++) {
- // Device is already open
- return;
- }
-
- if ((audio_mp = CreatePort (NULL, 0)) == NULL ||
- (audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
- MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- {
- fprintf(stderr,"SoundInit error 1\n");
- return;
- }
-
- chans[0] = 3;
-
-
- audio_io->ioa_Request.io_Message.mn_ReplyPort = audio_mp;
- audio_io->ioa_Request.io_Message.mn_Node.ln_Pri = 127;
- audio_io->ioa_AllocKey = 0;
- audio_io->ioa_Data = chans;
- audio_io->ioa_Length = sizeof(chans);
-
- if (OpenDevice((const char *) AUDIONAME, 0, (struct IORequest *)audio_io, 0) != 0) // [SHA, 03/10/2002 : PPC compilation]
- {
- #if PRINT
- fprintf(stderr,"OpenDevice(\"audio.device\") failed. Sound disabled.\n");
- #endif
- return;
- }
-
- audio_is_open = TRUE;
-
-
- for (i = 0; i < 2; i++)
- {
- c = &channel_info[i];
- if ((c->audio_mp = CreatePort (NULL, 0)) == NULL ||
- (c->audio_io = (struct IOAudio *)AllocMem(sizeof(struct IOAudio),
- MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- {
- fprintf(stderr,"SoundInit error 2\n");
- return;
- }
- *c->audio_io = *audio_io;
- c->audio_io->ioa_Request.io_Message.mn_ReplyPort = c->audio_mp;
- c->audio_io->ioa_Request.io_Unit = (struct Unit *)(1 << i);
- }
-
-
- if ((GfxBase->DisplayFlags & NTSC) != 0)
- clock_constant = 3579545; /* NTSC */
- else
- clock_constant = 3546895; /* PAL */
-
- dsp = 1; /* pretend we've opened the Linux sound device... */
-
- // Set stereo channel
- if (flags & AMIGAFLAG_MONO)
- stereo = 0; // mono sound
- else
- stereo = 1; // stereo
-
- // Set sound rate in Hertz
- soundRate = 11000;
- amiga_period = ((clock_constant << 1) + soundRate) / (((unsigned long) soundRate) << 1);
-
- blockSize = 64 * 1024; /* 64K ??????????????? */
-
- if (stereo)
- {
- /* RESULT NOT CHECKED!! */
- buffer1 = (char *) AllocVec(blockSize, MEMF_CHIP);
- buffer2 = (char *) AllocVec(blockSize, MEMF_CHIP);
- buffer = buffer1;
- }
- else
- {
- buffer = (char *) AllocVec(blockSize, MEMF_CHIP);
- }
-
- #if PRINT
- int caps;
-
- ioctl(dsp,SNDCTL_DSP_GETCAPS, &caps);
- printf("Audio capabilities = %x\n", caps);
- printf("Sound Rate = %d\n", soundRate);
- printf("Stereo = %d\n", stereo);
- printf("Sample Size = %d\n", sampleSize);
- printf("Buffer Size = %d\n", blockSize);
- #endif /* PRINT */
-
- #endif /* NOSOUND */
-
- #endif /* AMIGA */
- }
-
- #ifdef AMIGA
- void static AmigaStopSound(int handle)
- {
- struct channel_info *c;
-
- if (channel_info[handle].sound_in_progress)
- {
- /* Set the volume to 0 before aborting the audio, else we'll get a 'click' */
- // audio_io->ioa_Request.io_Command = ADCMD_PERVOL;
- // audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
- // audio_io->ioa_Request.io_Unit = (struct Unit *)(1 << handle);
- // audio_io->ioa_Period = amiga_period;
- // audio_io->ioa_Volume = 0;
- // BeginIO ((struct IORequest *)audio_io);
- // WaitPort (audio_mp);
- // GetMsg (audio_mp);
-
- /*
- if (!CheckIO((struct IORequest *)channel_info[handle].audio_io))
- {
- printf("already playing. Waiting\n");
- WaitPort (channel_info[handle].audio_mp); // clears signal & returns immediately
- GetMsg (channel_info[handle].audio_mp);
- printf("finished\n");
- channel_info[handle].sound_in_progress = FALSE;
- return;
- }
-
- printf("Aborting\n");
- */
-
- AbortIO ((struct IORequest *)channel_info[handle].audio_io);
- WaitPort (channel_info[handle].audio_mp);
- GetMsg (channel_info[handle].audio_mp);
- channel_info[handle].sound_in_progress = FALSE;
- }
- }
- #endif
-
- SoundMixer::~SoundMixer()
- {
- #ifndef AMIGA
- if (--nbInst == 0) {
- if (dsp > 0) {
- close(dsp);
- free(buffer);
- }
- }
- #else
- int i;
- if (--nbInst == 0)
- {
- if (audio_is_open)
- {
- for (i = 0; i < 2; i++) AmigaStopSound (i);
- audio_io->ioa_Request.io_Unit = (struct Unit *) ((1 << 2) - 1); /* free numChannels channels */
- CloseDevice ((struct IORequest *)audio_io);
- audio_is_open = FALSE;
- }
-
- for (i = 0; i < 2; i++)
- {
- if (channel_info[i].audio_io != NULL)
- {
- FreeMem (channel_info[i].audio_io, sizeof(struct IOAudio));
- channel_info[i].audio_io = NULL;
- }
- if (channel_info[i].audio_mp != NULL)
- {
- DeletePort (channel_info[i].audio_mp);
- channel_info[i].audio_mp = NULL;
- }
- }
-
- if (audio_io != NULL)
- {
- FreeMem (audio_io, sizeof(struct IOAudio));
- audio_io = NULL;
- }
- if (audio_mp != NULL)
- {
- DeletePort (audio_mp);
- audio_mp = NULL;
- }
-
- if (buffer1)
- {
- FreeVec(buffer1);
- buffer1 = (char *) NULL;
- }
-
- if (buffer2)
- {
- FreeVec(buffer2);
- buffer2 = (char *) NULL;
- }
- }
- #endif
- }
-
- void
- SoundMixer::stopSounds()
- {
- #ifndef NOSOUND
- SoundList *sl,*del;
-
- for(sl = list; sl; ) {
- del = sl;
- sl = sl->next;
- delete del;
- }
- list = 0;
- #endif
- }
-
- void
- SoundMixer::startSound(Sound *sound)
- {
- #ifndef NOSOUND
- SoundList *sl;
-
- if (sound) {
- // Add sound in list
- sl = new SoundList;
- sl->rate = sound->getRate();
- sl->stereo = (sound->getChannel() == 2);
- sl->sampleSize = sound->getSampleSize();
- sl->current = sound->getSamples();
- sl->remaining = sound->getSampleSize()*sound->getNbSamples()*sound->getChannel();
- sl->next = list;
- list = sl;
- }
- #endif
- }
-
- long
- SoundMixer::playSounds()
- {
- #ifndef NOSOUND
- #ifndef AMIGA
- audio_buf_info bufInfo;
- #endif
- long nbBytes, n;
- SoundList *sl,*prev;
- int status;
-
- // Init failed
- if (dsp < 0) return 0;
-
- // No sound to play
- if (list == 0) return 0;
-
- #ifndef AMIGA
- // Get free DMA buffer space
- status = ioctl(dsp, SNDCTL_DSP_GETOSPACE, &bufInfo);
-
- // Free space is not large enough to output data without blocking
- // But there are still sounds to play. We must wait.
- if (bufInfo.bytes < blockSize) return 1;
- #endif
-
- nbBytes = 0;
-
- // Fill buffer with silence.
- memset((void*)buffer, 0, blockSize);
-
- prev = 0;
- sl = list;
- while(sl) {
-
- // Ask sound to fill the buffer
- // according to device capabilities
- n = fillSoundBuffer(sl, buffer, blockSize);
-
- // Remember the largest written size
- if (n > nbBytes) {
- nbBytes = n;
- }
-
- // No more samples for this sound
- if (sl->remaining == 0) {
- // Remove sound from list
- if (prev) {
- prev->next = sl->next;
- delete sl;
- sl = prev->next;
- } else {
- list = sl->next;
- delete sl;
- sl = list;
- }
- } else {
- sl = sl->next;
- }
- }
-
- if (nbBytes) {
- #ifndef AMIGA
- // At last ! Play It !
- write(dsp,buffer,nbBytes);
- status = ioctl(dsp, SNDCTL_DSP_POST);
- #else
- struct channel_info *c;
- int ss;
- UBYTE *lbuffer,*rbuffer;
-
- if (stereo)
- {
- ss = nbBytes >> 1; /* buffer contains both the left & right channels, so the length is halved */
- lbuffer = (UBYTE *) buffer;
- rbuffer = (UBYTE *) buffer + (blockSize >> 1);
- }
- else
- {
- /* mono */
- ss = nbBytes;
- lbuffer = (UBYTE *) buffer;
- rbuffer = (UBYTE *) buffer;
- }
-
- #if PRINT
- printf("playing ladr=%p radr=%p len=%d (%d) stereo=%d\n",lbuffer,rbuffer,nbBytes, ss,stereo);
- #endif
-
- /* Wait for the sample to stop playing??? */
- AmigaStopSound(0);
- c = &channel_info[0];
- c->audio_io->ioa_Request.io_Command = CMD_WRITE;
- c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
- c->audio_io->ioa_Data = lbuffer;
- c->audio_io->ioa_Length = ss;
- c->audio_io->ioa_Period = amiga_period;
- c->audio_io->ioa_Volume = 63;
- c->audio_io->ioa_Cycles = 1;
- //BeginIO ((struct IORequest *)c->audio_io);
- SendIO ((struct IORequest *)c->audio_io);
-
- c->sound_in_progress = TRUE;
-
- AmigaStopSound(1);
- c = &channel_info[1];
- c->audio_io->ioa_Request.io_Command = CMD_WRITE;
- c->audio_io->ioa_Request.io_Flags = ADIOF_PERVOL;
- c->audio_io->ioa_Data = rbuffer;
- c->audio_io->ioa_Length = ss;
- c->audio_io->ioa_Period = amiga_period;
- c->audio_io->ioa_Volume = 63;
- c->audio_io->ioa_Cycles = 1;
- // BeginIO ((struct IORequest *)c->audio_io);
- SendIO ((struct IORequest *)c->audio_io);
- c->sound_in_progress = TRUE;
-
- if (stereo)
- {
- /* switch 'buffer' to point to the correct sound buffer */
- if (buffer == buffer1)
- buffer = buffer2;
- else
- buffer = buffer1;
- }
- #endif
- }
-
- return nbBytes;
- #else
- return 0;
- #endif
- }
-
- long
- SoundMixer::fillSoundBuffer(SoundList *sl, char *buff, long buffSize)
- {
- long sampleLeft, sampleRight;
- long skipOut, skipOutInit;
- long skipIn, skipInInit;
- long freqRatio;
- long totalOut = 0;
-
- sampleLeft = sampleRight = 0;
- skipOutInit = skipInInit = 0;
-
- freqRatio = sl->rate / soundRate;
- if (freqRatio) {
- skipOutInit = freqRatio - 1;
- skipInInit = 0;
- }
-
- freqRatio = soundRate / sl->rate;
- if (freqRatio) {
- skipInInit = freqRatio - 1;
- skipOutInit = 0;
- }
-
- skipOut = skipOutInit;
- skipIn = skipInInit;
- while (buffSize && sl->remaining) {
- if (skipIn-- == 0) {
- // Get sampleLeft
- if (sl->sampleSize == 2) {
- sampleLeft = (long)(*(short *)(sl->current));
- if (sampleSize == 1) {
- sampleLeft = (sampleLeft >> 8) &0xff;
- }
- } else {
- sampleLeft = (long)*(sl->current);
- if (sampleSize == 2) {
- sampleLeft <<= 8;
- }
- }
- sl->current += sl->sampleSize;
- sl->remaining -= sl->sampleSize;
-
- if (sl->stereo) {
- // Get sampleRight
- if (sl->sampleSize == 2) {
- sampleRight = (long)(*(short *)(sl->current));
- if (sampleSize == 1) {
- sampleRight = (sampleRight >> 8) &0xff;
- }
- } else {
- sampleRight = (long)*(sl->current);
- if (sampleSize == 2) {
- sampleRight <<= 8;
- }
- }
- sl->current += sl->sampleSize;
- sl->remaining -= sl->sampleSize;
-
- } else {
- sampleRight = sampleLeft;
- }
-
- skipIn = skipInInit;
- }
-
- if (skipOut-- == 0) {
- // Output
- if (stereo) {
- if (sampleSize == 2) {
- *((short *)buff) += sampleLeft/2;
- buffSize -= sampleSize;
- buff += sampleSize;
- *((short *)buff) += sampleRight/2;
- buffSize -= sampleSize;
- buff += sampleSize;
- } else {
- *((char *)buff) += sampleLeft/2;
- buffSize -= sampleSize;
- buff += sampleSize;
- *((char *)buff) += sampleRight/2;
- buffSize -= sampleSize;
- buff += sampleSize;
- }
- totalOut += 2*sampleSize;
- } else {
- if (sampleSize == 2) {
- *((short *)buff) += (sampleLeft+sampleRight)>>2;
- buffSize -= sampleSize;
- buff += sampleSize;
- } else {
- *((char *)buff) += (sampleLeft+sampleRight)>>2;
- buffSize -= sampleSize;
- buff += sampleSize;
- }
- totalOut += sampleSize;
- }
-
- skipOut = skipOutInit;
- }
- }
-
- return totalOut;
- }
-